#ifndef PROCESS_H_
#define PROCESS_H_

#include "System.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <queue>

#include "dispatcher.h"

using namespace std;

class Process
{
private:
	System* sys;
	queue< vector<string> > inbox;
	pthread_t m_thread;
	pthread_mutex_t	m_InboxLock;
	pthread_cond_t	m_InboxCond;

	bool busy;

	//int proc;
	int fdTable[12];//={-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1}; //12
	char cwd[256];
	int proc;

	char* getFullPath(char* buf, const char* dirname);
	int getLowestFreeFd();

public:
	Process(System* sys);
	Process(System* sys, Process* parent);
	virtual ~Process();

	const char* getCurrentWorkingDirectoryForTomer();
	//int getCurrentActiveProcessForTomer();
	void status();

	void enqueCmd(vector<string> args);
	bool isBusy();

	void run();
	void start();


	int fd();

	int mkdir(const char* dirname);

	//creates an empty file. Returns a file descriptor <fd>.
	int create(const char* filename, int flags);

	//- creates a hard link to file-to-link-to.
	//Making a hard link to directories is not allowed.
	int hdlink(const char* target, const char* linkname);//<file-to-link-to><new-file-name>

	// -creates a soft link to dest-to-link-to.
	//dest can be either a directory or a file.
	int sflink(const char* target, const char* linkname);//<dest-to-link-to><new-file-name>

	//- opens an existing file returning a file descriptor <fd>.
	//The fd returned should always be the lowest one still free.
	//Flag can be set to "read-only" or "read-and-write".
	//Always remember to check when reading or writing that the file was actually
	//opened for that purpose, otherwise return an error. Your flags should be in
	//the exact syntax specified.
	int open(const char* filename, int flag);

	// - close the file associated with the given file descriptor.
	//Release locks on this file held by this process.
	int close(int fd);

	//Read num-bytes from the file that is identified by fd.
	//Returns the string read, followed by a newline and then the number of bytes
	//that were actually read. Remember read uses the current file
	//pointer to know where to start reading from, and the operation
	//advances the file pointer. The output should be shown on stdofdut.
	int read(int fd, int nBytes);

	// - writes the string to the file. Returns the number of bytes actually written.
	//Remember write uses the current file pointer to know where to start writing from,
	//and the operation advances the file pointer.
	int write(int fd, const char* string);


	// -imports a real file from linux's file system from the given address into the file fd.
	//In this way files can be imported into the system.
	int writeFile(int fd,  const char* realfile);

	// <file-name> - deletes the file.
	int rm(const char* filename);

	// - deletes the directory. A directory can only be deleted if it is empty.
	int rmdir(const char* dirname);

	// - recursively deletes directory, all sub-directories and all files.
	//If one of the files is open, terminate and return error. It is o.k.
	//if the system starts deleting files and then finds one open, to then return an error.
	//This means that the command may be executed partially.
	int rmdir_r(const char* dirname);

	// - returns a list of the files in the given directory, each file in a different
	//line and including the file-name and its size (in bytes). If ls is given
	//without an argument, the ls of the current directory should be returned.
	//Output should be as follows: each file/dir in the given directory in a separate line,
	//directories have the "/" char appended to the end of their name.
	int ls(const char* dirname);
	int ls(const char*dirname, char* buf);
	// - changes the old-file-name to new file name. This can be just changing its
	//name in the same directory, or even moving the file to a different directory.
	int mv(const char *oldfilename, const char* newfilename);

	// - changes current working directory of the current process to new-directory.
	int cd(const char* dirname);



	// locks file, so that only read operations are allowed.
	//There is no limit on the number of processes permitted to read the file.
	//No processes are allowed to write to the file while a process holds a read
	//lock to the file. It is not obligatory to lock the file to read it.
	//You should not block if it is locked, rather return an error.
	int lck_rd(int fd);


	//locks file, so that only one process may hold the lock.
	//This process may write to the file, and no other processes may write to it
	//or read from it. A child does not inherit this lock.
	//It is not obligatory to lock the file to write to it.
	//You should not block if it is locked, rather return an error.
	int lck_wr(int fd);


	//releases the reading lock held by this process.
	//No other process may release this lock.
	int rlslck_rd(int fd);


	//releases the writing lock held by this process.
	//Only the process which locked the file may release the lock.
	int rlslck_wr(int fd);

	// moves the file pointer to the given offset from start of file.
	//If the pointer is set to an offset after the end of the file, this is o.k.
	//If data is later written at this point, subsequent reads of the data in the gap
	//return bytes of zeros (until data is actually written into the gap).
	//The size of the file should not be updated until data is written to that point.
	int lseek(int fd, int offset);





	// - Switches to the context of a different process.
	//Make sure to also switch to the new process' fd table and working directory.
	//int swprc(int procNum);

	// -Creates a process with the given id. If a process with this id already exists,
	//return an error. If parent == -1, this process is created with no open files.
	//If parent > -1, this process is defined as the child of the process with id parent.
	//This means that it is created with an exact copy of the fd table of the parent.
	//If process with id parent doesn’t exist return an error.
	//This function doesn’t switch to the context of the newly created process,
	//rather it stays in the context of the current process.
	//int crprc(int id, int parent);

};

#endif /*PROCESS_H_*/
